import {
  useCall,
  useDebounceValue,
  useEffectRef,
  useForceUpdate,
  useReq,
  useSaveQuery,
  useSimpleMemo,
  useTableActions,
  useTableColumns,
  useWillMountEffect,
} from '@/components';
import { TABLE_KEYS } from '@/constants/componentKeys';
import {
  createNextTickOnce,
  filterNullKey,
  forkHandler,
  getQueryValue,
  getType,
  isEqual,
  isNull,
  map,
  pick,
  simpleMerge,
} from '@/utils';
import { Table } from 'antd';
import * as PropTypes from 'prop-types';
import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
import { useHistory } from 'react-router-dom';

const defaultPagerToData = (current, pageSize) => [{ current, pageSize }];
const defaultSortToData = (sort) => [
  {
    sortParams: sort.order
      ? {
          [sort.field]: sort.order === 'ascend',
        }
      : {},
  },
];
const defaultResultToList = (result) => result?.data?.records;
const defaultResultToTotal = (result) => result?.data?.total ?? 0;

const getDefaultSort = (columns) =>
  columns.reduce(
    (ret, col) => (col.defaultSortOrder ? { field: col.dataIndex, order: col.defaultSortOrder } : ret),
    {},
  );

const isEmptyObject = (object) =>
  getType(object) === 'Object' &&
  Object.keys(object)
    .filter((k) => object[k] != null && !isEmptyObject(object[k]))
    .toString() === '';

// isEqualData({ a: {}, b: 1}, { a: null, b: 1}) === true
const isEqualData = (a, b) =>
  isEqual(a, b, {
    deep: true,
    compare(a, b) {
      if (a == b) return true;
      if (a == null || isEmptyObject(a)) return b == null || isEmptyObject(b);
      return false;
    },
  });

function PaginationTable(props, ref) {
  let {
    component: Comp = Table,

    // 请求相关
    service = null,
    serviceOptions = null,
    serviceData = null,
    pagerToData = defaultPagerToData,
    sortToData = defaultSortToData,
    resultToList = defaultResultToList,
    resultToTotal = defaultResultToTotal,
    manually = false,

    columns = [],

    // 操作列
    actions,
    actionTitle = '操作',
    actionCol = null,
    actionWidth,

    // 忽略这个参数
    dataSource: __ignore,

    rowKey = 'id',
    onChange,

    ...rest
  } = props;
  const [tableProps, others] = pick(rest, TABLE_KEYS);

  const pageNo = getQueryValue(useHistory().location.search, 'pageNo') || '1';
  const currentRef = useRef(parseInt(pageNo));
  useSaveQuery('pageNo', currentRef.current);
  const pageSize = getQueryValue(useHistory().location.search, 'pageSize') || '10';
  const pageSizeRef = useRef(parseInt(pageSize));
  useSaveQuery('pageSize', pageSizeRef.current);

  const sortRef = useRef(getDefaultSort(columns));
  const update = useForceUpdate();
  const xhr = useReq(service, serviceOptions);
  const pagerData = useCall(pagerToData, currentRef, pageSizeRef)();
  const sortData = useCall(sortToData, sortRef)();

  if (getType(serviceData?.[0]?.t) === 'Object') {
    serviceData[0].t = filterNullKey(serviceData[0].t, isNull);
  }

  if (getType(serviceData?.[0]?.searchFuzzy) === 'Object') {
    serviceData[0].searchFuzzy = filterNullKey(serviceData[0].searchFuzzy, isNull);
  }

  const responseCount = useRef(-1); // 记录异步请求成功/失败的次数, cancel continue的不算.
  useEffect(() => {
    responseCount.current += 1;
  }, [xhr.result, xhr.error]);

  useEffect(() => {
    // 首次的页码从url获取默认值
    if (responseCount.current > 0) currentRef.current = 1;
    update();
  }, [useDebounceValue(useSimpleMemo(serviceData), isEqualData)]);
  const serviceDataMemo = useSimpleMemo(
    simpleMerge([{}], ...[serviceData, pagerData, sortData].filter(Boolean)),
    isEqualData,
  );
  const serviceDataRef = useEffectRef(serviceDataMemo);

  const refresh = useMemo(() => createNextTickOnce(() => xhr.start(...serviceDataRef.current)), []);
  const goPage = useCall((current) => {
    currentRef.current = current;
    refresh();
  });
  const nextPage = useCall(() => {
    currentRef.current = Math.min(Math.ceil(total / pageSizeRef.current), currentRef.current + 1);
    refresh();
  });
  const prevPage = useCall(() => {
    currentRef.current = Math.max(1, currentRef.current - 1);
    refresh();
  });

  const total = resultToTotal(xhr.result);
  const resultList = useSimpleMemo(resultToList(xhr.result) ?? []);
  const [dataSource, setData] = useState(resultList);

  useWillMountEffect(xhr.startOnce, ...serviceDataMemo);

  useEffect(() => {
    if (!manually) refresh();
  }, [serviceDataMemo]);

  useEffect(() => {
    setData(resultList);
  }, [resultList]);

  const getXhr = useCall(() => xhr);
  const getData = useCall(() => dataSource);
  const instance = useRef({
    getXhr,
    getData,
    setData,
    refresh,
    nextPage,
    prevPage,
    goPage,
  }).current;

  useImperativeHandle(ref, () => instance);

  const handleChange = (pagination, filter, sort) => {
    if (currentRef.current !== pagination.current) {
      currentRef.current = pagination.current;
    }
    if (pageSizeRef.current !== pagination.pageSize) {
      pageSizeRef.current = pagination.pageSize;
      currentRef.current = 1;
    }

    sortRef.current = sort;

    update();
  };

  let $others = { ...others };
  map($others, (value, key) => {
    if (typeof value === 'string' && key.startsWith('on') && Object.hasOwnProperty.call(instance, value)) {
      $others[key] = instance[value];
    }
  });
  const colWithActions = useSimpleMemo(
    useTableColumns(columns).concat(
      useTableActions(actions, $others, { width: actionWidth, ...actionCol }, actionTitle, instance),
    ),
  );

  return (
    <Comp
      loading={xhr.status === 'loading'}
      dataSource={dataSource}
      columns={colWithActions}
      rowKey={rowKey}
      total={total}
      onChange={useCall(forkHandler(onChange, handleChange, true))}
      {...useSimpleMemo({
        ...tableProps,
        scroll: {
          x: '100%',
          ...tableProps.scroll,
        },
        pagination: {
          total,
          current: currentRef.current,
          pageSize: pageSizeRef.current,
          showSizeChanger: true,
          showQuickJumper: true,
          showTotal: useCall((t) => `共 ${t} 条`),
        },
      })}
    />
  );
}

PaginationTable = forwardRef(PaginationTable);

PaginationTable.propTypes = {
  /** 请求 */
  service: PropTypes.any,
  serviceOptions: PropTypes.any,
  /** 固定请求参数 */
  serviceData: PropTypes.any,

  /** 分页参数 */
  pagerToData: PropTypes.func,

  /** 排序参数 */
  sortToData: PropTypes.func,

  /** 请求结果转表格数据 */
  resultToList: PropTypes.func,

  /** 请求结果转总条数 */
  resultToTotal: PropTypes.func,

  /** 手动触发请求 */
  manually: PropTypes.bool,

  /** 表格列配置 */
  columns: PropTypes.arrayOf(PropTypes.any),

  /** 表格操作列配置 */
  actions: PropTypes.any,
  actionTitle: PropTypes.string,
  actionCol: PropTypes.object,
  actionWidth: PropTypes.number,

  rowKey: PropTypes.string,
  onChange: PropTypes.any,
};

export default PaginationTable;
